using System;
using System.Text;
using System.Data;
using System.Collections;
using System.Collections.Generic;

using Framework;

namespace SchemaMonitor
{
    //Table-Row Class (Customisable half)
    public partial class CChange
    {
        #region Constants
        //Join Expressions
        private static string JOIN_NODE = String.Concat(TABLE_NAME, " INNER JOIN ", CNode.TABLE_NAME, " ON ChangeNodeGuid=NodeGuid AND ChangeTypeId=NodeTypeId");
        #endregion

        #region Constructors (Public)
        //Default Connection String
        public CChange() : base() {}
        public CChange(long changeId) : base(changeId) {}
        
        //Alternative Connection String
        public CChange(CDataSrc dataSrc) : base(dataSrc) {}
        
        public CChange(CDataSrc dataSrc, long changeId) : base(dataSrc, changeId) {}
        
        //Transactional (shares an open connection)
        protected internal CChange(CDataSrc dataSrc, long changeId, IDbTransaction txOrNull) : base(dataSrc, changeId, txOrNull) {}        

        //Custom
        public CChange(CNode node, CDiffList diff)
        {
            this.ChangeNodeGuid = node.NodeGuid;
            this.ChangeTypeId = node.NodeTypeId;
            this.Diff = diff;
        }
        #endregion

        #region Default Values
        protected override void InitValues_Custom()
        {
            //Custom default values (e.g. DateCreated column)
            _changeDetected = DateTime.Now;
            //Member variables (e.g. for child collections)
        }
        #endregion
        
        #region Default Connection String
        protected override CDataSrc DefaultDataSrc()  { return CDataSrc.Default;  }
        #endregion

        #region Members
        //Foreign Keys
        private CNode _node;
        
        //Child Collections  
        
        //Xml Data (as high-level objects)
        
        #endregion

        #region Properties - Relationships
        //Relationships - Foriegn Keys (e.g parent)
        public CNode Node
        {
            get
            {
                if (null == _node)
                    _node = new CNode(ChangeNodeGuid);
                return _node;
            }
        }

        //Relationships - Collections (e.g. children)
        
        #endregion

        #region Properties - Customisation
        //Derived/ReadOnly (e.g. xml classes, presentation logic)
        public CDiffList Diff
        {
            get
            {
                return CProto.Deserialise<CDiffList>(ChangeDataAuto);
            }
            set
            {
                ChangeDataAuto = CProto.Serialise(value);
            }
        }
        public byte[] ChangeDataAuto
        {
            get
            {
                if (this.ChangeData == null)
                    return null;
                if (this.ChangeDataIsGz)
                    return CBinary.Unzip(this.ChangeData);
                return this.ChangeData;
            }
            set
            {
                this.ChangeData     = value;
                this.ChangeDataIsGz = false;
                if (value.Length > 128)
                {
                    var gz = CBinary.Zip(value);
                    if (gz.Length * 1.05 < value.Length)
                    {
                        this.ChangeData = gz;
                        this.ChangeDataIsGz = true;
                    }
                }
            }
        }
        #endregion

        #region Save/Delete Overrides
        //Can Override base.Save/Delete (e.g. Cascade deletes, or insert related records)
        #endregion

        #region Custom Database Queries
        //For Stored Procs can use: MakeList (matching schema), or DataSrc.ExecuteDataset (reports etc)
        //For Dynamic sql, can use: SelectSum, SelectDistinct, SelectCount, SelectWhere (inherited methods)
        //                see also: SelectBy[FK], Search and Count (auto-generated sample queries)
        public CChangeList SelectByUser(CPagingInfo pi, long userId)
        {
            pi.TableName = JOIN_NODE;
            return SelectWhere(pi, new CCriteria("NodeUserId", userId));
        }
        public CChangeList SelectByUser(CPagingInfo pi, long userId, int typeId)
        {
            pi.TableName = JOIN_NODE;
            var where = new CCriteriaList(3);
            where.Add("NodeTypeId", typeId);
            where.Add("NodeUserId", userId);
            where.Add("ChangeTypeId", typeId);
            return SelectWhere(pi, where);
        }
        #endregion

        #region Searching (Optional)
        //Dynamic search methods: (overload as required for common search patterns, cascade the BuildWhere overloads)
        //   Public  x5 - Simple, Paged, Transactional, Count, and Dataset
        //   Private x1 - BuildWhere
        //See also in-memory search options in list class, such as GetBy[FK] and Search

        //Simple
        public CChangeList SelectSearch(string nameOrId /*, nodeId, typeId*/)  {   return SelectWhere(BuildWhere(nameOrId /*, nodeId, typeId*/));  } //, JOIN_OR_VIEW); }

        //Paged
        public CChangeList SelectSearch(CPagingInfo pi, string nameOrId /*, long nodeId, int typeId */)
        {
            //pi.TableName = JOIN_OR_VIEW
            return SelectWhere(pi, BuildWhere(nameOrId /*, nodeId, typeId*/));
        }

        //Transactional
        public CChangeList SelectSearch(string nameOrId, /* long nodeId, int typeId, */ IDbTransaction tx)   {   return SelectWhere(BuildWhere(nameOrId /*, , nodeId, typeId */), tx);   }   //, JOIN_OR_VIEW, tx); }

        //Dataset (e.g. ExportToCsv)
        public DataSet SelectSearch_Dataset(string nameOrId /*, long nodeId, int typeId*/)   {   return SelectWhere_Dataset(BuildWhere(nameOrId /*, , nodeId, typeId */));   }   //, JOIN_OR_VIEW); }

        //Count
        public int SelectCount(string nameOrId /*, long nodeId, int typeId*/)   {   return SelectCount(BuildWhere(nameOrId /*, , nodeId, typeId */));   }   //, JOIN_OR_VIEW); }

        //Filter Logic
        private CCriteriaList BuildWhere(string nameOrId /*, long nodeId, int typeId */)
        {
            CCriteriaList where = new CCriteriaList();  //Defaults to AND logic
            
            //Simple search box UI
            if (!string.IsNullOrEmpty(nameOrId)) 
            {
                //Interpret search string in various ways using OR sub-expression
                CCriteriaGroup orExpr = new CCriteriaGroup(EBoolOperator.Or);
                
                //Special case - search by PK
                /* 
                int id = 0;
                if (int.TryParse(nameOrId, out id))
                    orExpr.Add("ChangeId", id); 
                */
                
                //Search a range of string columns
                string wildCards = string.Concat("%", nameOrId, "%");

                //Conclude
                if (orExpr.Group.Count > 0)
                    where.Add(orExpr);
            }
            
			//Other search Colums (customise as required)
            //if (long.MinValue != nodeId)   where.Add("ChangeNodeGuid", nodeId);
            //if (int.MinValue != typeId)   where.Add("ChangeTypeId", typeId);

            return where;
        }
        #endregion


        #region Cloning
        public CChange Clone(CDataSrc target, IDbTransaction txOrNull) //, int parentId)
        {
            //Shallow copy: Copies the immediate record, excluding autogenerated Pks
            CChange copy = new CChange(this, target);

            //Deep Copy - Child Entities: Cloned children must reference their cloned parent
            //copy.SampleParentId = parentId;

            copy.Save(txOrNull);

            //Deep Copy - Parent Entities: Cloned parents also clone their child collections
            //this.Children.Clone(target, txOrNull, copy.ChangeId);

            return copy;
        }
        #endregion

        #region ToXml
        protected override void ToXml_Custom(System.Xml.XmlWriter w)
        {
            //Store(w, "Example", this..Example)
        }
        #endregion
    }
}